close all;
clear all;
img = imread("im1.jpg");

dimg = double(imread("im1.jpg"));

img = uint8(dimg);
% img = imcomplement(img);
figure;
imshow(img);
% laplacianFilter = fspecial('laplacian', 0.5);
% gaussianFilter = fspecial('gaussian', [1 1], 2);
% img = imfilter(img, gaussianFilter);
% se = strel('disk', 5);
% % img = imbothat(img,se);
% img = imtophat(img, se);



figure;
imshow(img);

threshold = 0.1; % 计算自适应阈值
binary_image_1 = imbinarize(img, threshold); % 二值化处理
figure;
imshow(binary_image_1);
% 
% se = strel('disk', 1); % 创建一个半径为2的圆形结构元素
% binary_image = imclose(binary_image_1, se); % 执行闭运算

% 使用bwlabel将二值图像中的连通区域进行标记
% labeledImage = bwlabel(binary_image, 8);
[pixelCoordinates, labeledImage, numLabels] = custom_bwlabel(binary_image_1);


disp(labeledImage);

% display
figure;
imshow(label2rgb(labeledImage, 'hsv', 'k', 'shuffle'));
title('Connected Components 48');


% 使用bwconncomp获取连通区域的属性
cc = bwconncomp(binary_image_1, 8);
connectedComponents = cc.PixelIdxList; % 获取每个连通区域的像素索引

% 判断cell中的元素个数
numElements = numel(connectedComponents);

% 如果元素个数大于5
if numElements > 5
    % 计算每个向量的维数
    dimensions = cellfun(@numel, connectedComponents);
    
    % 确定需要去掉的向量个数
    numToRemove = numElements - 5;
    
    % 从维数最小的向量开始去掉
    [~, sortedIndices] = sort(dimensions);
    removeIndices = sortedIndices(1:numToRemove);
    
    % 保留剩余的向量
    connectedComponents(removeIndices) = [];
end


% 显示连通区域的标记图像
figure;
imshow(label2rgb(labeledImage, 'hsv', 'k', 'shuffle'));
title('Connected Components');

cellSize = numel(connectedComponents);

% 遍历每个连通区域

for i = 1:numel(connectedComponents)
    % 创建一个与原始图像大小相同的全黑图像
    output_image = zeros(size(img, 1), size(img, 2));
    % 获取当前连通区域的像素索引
    pixelIdxList = connectedComponents{1,i};
    
    % 将当前连通区域的像素设置为白色
    output_image(pixelIdxList) = 1;
    % 显示结果图像
    figure;
    imshow(output_image);
    title('Individual Connected Components');
end



% 如果元素个数大于5
if numLabels > 5
    % 计算每个向量的维数
    dimensions = cellfun(@numel, pixelCoordinates);
    
    % 确定需要去掉的向量个数
    numToRemove = numLabels - 5;
    
    % 从维数最小的向量开始去掉
    [~, sortedIndices] = sort(dimensions);
    removeIndices = sortedIndices(1:numToRemove);
    
    % 保留剩余的向量
    pixelCoordinates(removeIndices) = [];
end

for label = 1:numLabels
    regionImage = zeros(size(img));
    % 获取当前连通区域的元素坐标集合
    coordinates = pixelCoordinates{label};
    
    % 将当前连通区域的像素设置为前景值
    for i = 1:size(coordinates, 1)
        row = coordinates(i, 1);
        col = coordinates(i, 2);
        regionImage(row, col) = 1;
    end

    S{label} = regionImage;
    
    % 显示当前连通区域的图像
    figure;
    imshow(regionImage);
    title('regionImage');
end

% 应用 Sobel 算子
edgeImage = edge(img, 'Sobel');

% se = strel('disk', 1); % 创建一个半径为1的圆形结构元素
% edgeImage = imclose(edgeImage, se); % 执行闭运算
% edgeImage = imopen(edgeImage, se); % 执行闭运算

% 将提取的轮廓应用到 RGB 图像上
resultImage = imoverlay(img, edgeImage, 'r');


% 显示结果图像
figure;
imshow(resultImage);
connComp = bwconncomp(edgeImage);
props = regionprops(connComp, 'PixelIdxList', 'BoundingBox');
numComponents = connComp.NumObjects;

% 创建一个标志矩阵，用于跟踪已连接的连通组件
connected = false(numComponents);

for i = 1:numComponents
    for j = i+1:numComponents
        bbox1 = props(i).BoundingBox;
        bbox2 = props(j).BoundingBox;
        
        % 检查边界框是否相交
        if bboxOverlap(bbox1, bbox2)
            connected(i, j) = true;
            connected(j, i) = true;
        end
    end
end
newConnComp = struct('PixelIdxList', {}, 'BoundingBox', {});

for i = 1:numComponents
    if ~any(connected(i, :))
        % 如果当前连通组件没有与其他连通组件连接，则保留它
        newConnComp(end+1) = connComp(i);
    else
        % 如果当前连通组件与其他连通组件连接，则将它们的像素索引合并
        connectedComponents = [i find(connected(i, :))];
        pixels = vertcat(connComp(connectedComponents).PixelIdxList);
        newConnComp(end+1).PixelIdxList = pixels;
        
        % 计算合并后的连通组件的边界框
        mergedBbox = computeMergedBoundingBox(props, connectedComponents);
        newConnComp(end).BoundingBox = mergedBbox;
    end
end
%%
% % 标记每个不同的轮廓
% labeledImage = bwlabel(edgeImage);
% 
% % 提取每个轮廓的属性
% props = regionprops(labeledImage, 'BoundingBox');
% 
% % 显示每个轮廓区域
% figure;
% imshow(binary_image); % 显示原始二值图像
% hold on;
% 
% for i = 1:numel(props)
%     % 获取当前轮廓的边界框
%     bb = props(i).BoundingBox;
%     
%     % 提取对应的图像区域
%     x = round(bb(1));
%     y = round(bb(2));
%     width = round(bb(3));
%     height = round(bb(4));
%     subImage = binary_image(y:y+height-1, x:x+width-1);
%     
%     % 显示当前轮廓的图像区域
%     figure;
%     imshow(subImage);
%     title(['Contour ', num2str(i)]);
% end
% % 显示结果图像
% figure;
% imshow(output_image);
% title('Individual Connected Components');